1   /*
2    * Copyright (C) 2012 The Guava Authors
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5    * in compliance with the License. You may obtain a copy of the License at
6    *
7    * http://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software distributed under the License
10   * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11   * or implied. See the License for the specific language governing permissions and limitations under
12   * the License.
13   */
14  
15  package com.google.common.hash;
16  
17  import static com.google.common.base.Preconditions.checkArgument;
18  import static com.google.common.base.Preconditions.checkNotNull;
19  
20  import com.google.common.base.Supplier;
21  
22  import java.io.Serializable;
23  import java.util.zip.Checksum;
24  
25  /**
26   * {@link HashFunction} adapter for {@link Checksum} instances.
27   *
28   * @author Colin Decker
29   */
30  final class ChecksumHashFunction extends AbstractStreamingHashFunction implements Serializable {
31  
32    private final Supplier<? extends Checksum> checksumSupplier;
33    private final int bits;
34    private final String toString;
35  
36    ChecksumHashFunction(Supplier<? extends Checksum> checksumSupplier, int bits, String toString) {
37      this.checksumSupplier = checkNotNull(checksumSupplier);
38      checkArgument(bits == 32 || bits == 64, "bits (%s) must be either 32 or 64", bits);
39      this.bits = bits;
40      this.toString = checkNotNull(toString);
41    }
42  
43    @Override
44    public int bits() {
45      return bits;
46    }
47  
48    @Override
49    public Hasher newHasher() {
50      return new ChecksumHasher(checksumSupplier.get());
51    }
52  
53    @Override
54    public String toString() {
55      return toString;
56    }
57  
58    /**
59     * Hasher that updates a checksum.
60     */
61    private final class ChecksumHasher extends AbstractByteHasher {
62  
63      private final Checksum checksum;
64  
65      private ChecksumHasher(Checksum checksum) {
66        this.checksum = checkNotNull(checksum);
67      }
68  
69      @Override
70      protected void update(byte b) {
71        checksum.update(b);
72      }
73  
74      @Override
75      protected void update(byte[] bytes, int off, int len) {
76        checksum.update(bytes, off, len);
77      }
78  
79      @Override
80      public HashCode hash() {
81        long value = checksum.getValue();
82        if (bits == 32) {
83          /*
84           * The long returned from a 32-bit Checksum will have all 0s for its second word, so the
85           * cast won't lose any information and is necessary to return a HashCode of the correct
86           * size.
87           */
88          return HashCode.fromInt((int) value);
89        } else {
90          return HashCode.fromLong(value);
91        }
92      }
93    }
94  
95    private static final long serialVersionUID = 0L;
96  }